package org.kfish.framework.util;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ClassUtil {
	private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtil.class);

	/**
	 * 获取类
	 * 
	 * @return
	 */
	public static ClassLoader getClassLoader() {

		return Thread.currentThread().getContextClassLoader();
	}

	/**
	 * 加载类
	 * 
	 * @param className
	 * @param initialized
	 * @return
	 */
	public static Class<?> loadClass(String className, boolean initialized) {
		Class<?> cls;
		try {
			cls = Class.forName(className, initialized, getClassLoader());
		} catch (ClassNotFoundException e) {
			LOGGER.error("load class failure", e);
			throw new RuntimeException(e);
		}
		return cls;
	}
	
	public static Class<?> loadClass(String className){
		//为 true 表示在加载类的时候，初始化类，会执行static block 中的代码
		return loadClass(className,true);
	}

	/**
	 * 获取指定包下的所有类
	 * 
	 * @param packageName
	 * @return
	 */
	public static Set<Class<?>> getClassSet(String packageName) {
		// 不允许重复
		Set<Class<?>> classSet = new HashSet<>();
		try {
			// replace为替换所有，并不是只替换第一个匹配的值
			Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".", "/"));

			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
				if (url != null) {
					// 如 http://的protocol 为http ; file:// 的 protocol 为 file
					String protocol = url.getProtocol();
					if (protocol.equals("file")) {
						// url 空格会被替换成%20，这里替换回去
						String packagePath = url.getPath().replaceAll("%20", " ");
						addClass(classSet, packagePath, packageName);
					} else if (protocol.equals("jar")) {
						JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();

						if (jarURLConnection != null) {
							JarFile jarFile = jarURLConnection.getJarFile();
							if (jarFile != null) {
								Enumeration<JarEntry> jarEntries = jarFile.entries();
								while (jarEntries.hasMoreElements()) {
									JarEntry jarEntry = jarEntries.nextElement();
									String jarName = jarEntry.getName();
									if (jarName.endsWith(".class")) {
										String className = jarName.substring(0, jarName.lastIndexOf(".")).replace("/",
												".");
										doAddClass(classSet, className);
									}
								}
							}
						}
					}
				}
			}

		} catch (IOException e) {

			LOGGER.error("get class set failure ",e);
			throw new RuntimeException(e);
		}

		return classSet;
	}

	/**
	 * 递归将 classSet中的所有类加载
	 * 
	 * @param classSet
	 * @param packagePath
	 * @param packageName
	 */
	private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName) {

		// 文件过滤，只提取class文件和文件夹
		File[] files = new File(packagePath).listFiles(new FileFilter() {
			@Override
			public boolean accept(File file) {
				return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
			}
		});

		// 遍历，添加class 到classSet
		for (File file : files) {
			String fileName = file.getName();
			if (file.isFile()) {
				String className = fileName.substring(0, fileName.lastIndexOf("."));
				if (StringUtil.isNotEmpty(packageName)) {
					className = packageName + "." + className;
				}
				doAddClass(classSet, className);
			} else {
				// 是文件夹
				if (StringUtil.isNotEmpty(packagePath)) {
					String subPackageName = packageName+"."+fileName;
					String subPackgePath = packagePath + "/" + fileName;
					addClass(classSet, subPackgePath, subPackageName);
				}
			
			}
		}

	}

	private static void doAddClass(Set<Class<?>> classSet, String className) {
		Class<?> cls = loadClass(className, false);
		classSet.add(cls);
	}

}
